/*
 * Version 1.1.3
 * 
 * Fixes:
 * 1.1.1
 * 	# Implements OOP principles!
 *  # Configuration readable thru config.xml
 *  # Serial baud rate increased [115200 bps]
 *  # Package name moved from org.* to edu.*
 *  
 * 1.1.3
 * 	# Makes use of arguments
 *  # Connectivity between CORE and SQL
 *  # Cleaner code
 *  # JARable CORE code
 */

package edu.bulsu.coe;

import javax.smartcardio.CardException;

import edu.bulsu.coe.nfc.Card;
import edu.bulsu.coe.nfc.CardDB;
import edu.bulsu.coe.nfc.NFC;
import edu.bulsu.coe.serial.Arduino;
import edu.bulsu.coe.sql.SQL;

public class Source{
	public static void main(String args[]) throws InterruptedException{
		
		//[ERR] Code 500 Configuration not found on location
		//[ERR] Code 501 Configuration was overridden
		float circumferencePerRotation = 0f;
		Configurations basicConf = null;
		try{
			basicConf = new Configurations("config.xml");
			circumferencePerRotation = Float.parseFloat(basicConf.getParams("circumference")); 
		}catch(Exception e){
			System.exit(0);
		}
		
		Configurations sqlConf = null;
		try{
			sqlConf = new Configurations("sql.xml");
		}catch(Exception e){
			System.exit(0);
		}
		
		//[ERR] Code 100 Core cannot connect to given Arduino parameters
		Arduino arduino = null;
		String arduinoPort = basicConf.getParams("ardport");
		int arduinoBaud = Integer.parseInt(basicConf.getParams("ardbaud"));
		try{
			arduino = new Arduino(arduinoPort, arduinoBaud);
			arduino.clear();
		}catch(Exception spe){
			System.out.println("[CORE] Error 100: Cannot create arduino class, quitting");
			System.exit(0);
		}
		
		arduino.clear();
		arduino.writeScreen("Initializing...\nChecking SQL", 0, 0);
		String sqlAddress = sqlConf.getParams("sqladd");
		String sqlPort = sqlConf.getParams("sqlport");
		String sqlSID = sqlConf.getParams("sqlSID");
		String sqlUsername = sqlConf.getParams("sqluser");
		String sqlPassword = sqlConf.getParams("sqlpass");
		SQL sql = new SQL(sqlAddress, sqlPort, sqlSID, sqlUsername, sqlPassword);
		float regularFlatrate = sql.getRegularFlatrate();
		float seniorFlatrate = sql.getSeniorFlatrate();
		float studentFlatrate = sql.getStudentFlatrate();
		float disabledFlatrate = sql.getStudentFlatrate();
		
		//[ERR] Code 300 NFC reader disconnected before core is run
		arduino.cwriteScreen("Checking NFC", 0, 1);
		NFC nfc = null;
		try{
			nfc = new NFC();
			arduino.cwriteScreen("NFC Done", 0, 1);
		}catch(Exception ce){
			arduino.cwriteScreen("NFC Error, quitting\n\nError Number: 300", 0, 1);
			System.exit(0);
		}
		
		arduino.cwriteScreen("Creating Card DB", 0, 1);
		CardDB cardDB = new CardDB();
		arduino.cwriteScreen("Database created", 0, 1);
		
		while(true){
			arduino.clear();
			arduino.writeScreen("BulSU\n Bus Client 1.1.3\n    Tap NFC  now", 8, 0);
			
			int cardNumber = 0;
			
			//[ERR] Code 30 NFC reader disconnected while core is running [exclusive of CARDNOTPRESENT error]
			//[ERR] Code 312 NFC reader NullPointers whenever a card is tapped fast. [post 311 error]
			try{
				cardNumber = nfc.getCardNumber();
				if(cardNumber > 20000000) cardNumber = 1; 
				System.out.println("[CORE] Card Number: " + cardNumber);
			}catch(CardException ce){
				arduino.clear();
				arduino.writeScreen("=NFC   reader error=   \n\nError Number: 30");
				continue;
			}
			
			//Get card status
			String cardStatus = sql.getNFCStatus(cardNumber);
			if(cardStatus.equals("ACTIVATED")){
				//Access active cards
				arduino.clear();
				arduino.writeScreen("====================", 0, 0);
				System.out.println("[CORE] Distance: " + arduino.getRotation() * circumferencePerRotation);
				if(!cardDB.getCardPresence(cardNumber)){
					arduino.writeScreen("NFC  read, entry\nRegular: ", 2, 1);
					int regularCount = arduino.getKeypress();
					arduino.cwriteScreen("Student: ", 0, 2);
					int studentCount = arduino.getKeypress();
					arduino.cwriteScreen("Senior: ", 0, 2);
					int seniorCount = arduino.getKeypress();
					arduino.cwriteScreen("Disabled: ", 0, 2);
					int disabledCount = arduino.getKeypress();
					
					//Get value of debt
					float debt = sql.getDebt(cardNumber);
					float load = sql.getLoad(cardNumber);
					int totalPassengerCount = regularCount + studentCount + seniorCount + disabledCount;
					float totalFlatrate = regularCount * regularFlatrate +
							 			  seniorCount * seniorFlatrate +
							 			  studentCount * studentFlatrate +
							 			  disabledCount * disabledFlatrate;
					
					arduino.clear();
					if((load - totalFlatrate >= 0) && (debt == 0)){
						if(totalPassengerCount > 0){
							float kilometers = arduino.getRotation() * circumferencePerRotation;
							Card card =  new Card(cardNumber, kilometers, regularCount, studentCount, seniorCount, disabledCount);
							cardDB.activateCard(cardNumber, card);
							arduino.writeScreen("Transaction Complete Have  a safe trip! ", 0, 1);
						}else arduino.writeScreen(" No passenger count  Please input count   then remove NFC   ", 0, 0);
					}else arduino.writeScreen("\nLoad  insufficient\n Please remove NFC ", 1, 0);
				}else{
					Card card = cardDB.getCard(cardNumber);
					float distance = (arduino.getRotation() * circumferencePerRotation) - card.getCardDistance();
					float fare = sql.getFare(
							String.valueOf(cardNumber),
							distance,
							card.getCardStudentPC(),
							card.getCardDisabledPC(),
							card.getCardSeniorPC(),
							card.getCardRegularPC());
					arduino.writeScreen("NFC  read,  exit\nP:" +
							card.getCardTotalPC() +
							"     D:" + distance+"\nFare: Php" + fare, 2, 1);
					cardDB.deactivateCard(cardNumber);
				}
			}else{
				arduino.clear();
				arduino.writeScreen("\n   NFC  not valid\n Please remove NFC  ", 0, 0);
			}
			Thread.sleep(3000); //XXX I guess this is fine... for now.
		}
	}
}
